package com.javaee.ex05.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;


// 基于xml方式实现面向切面编程
// XmlAspect是切面，beforeAdvice是通知
@Component
@Aspect // 第四步：声明切面
public class AnnotationAspect {
    // 第一个步骤：通过@Pointcut注解和切点表达式定义切点
    @Pointcut("execution(* com.javaee.ex05.service.impl.BookServiceImpl.*(..))")
    public void pointcut() {}
    // 第二个步骤：通过注解+切点 为指定切点装配通知
    @Before("pointcut()")//pointcut()是定义切点的方法名
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("前置通知 beforeAdvice");
        System.out.println("目标类：" + joinPoint.getTarget());
        System.out.println("目标方法：" + joinPoint.getSignature().getName());
    }
    // 注意在环绕通知当中方法需要有返回值类型 ProceedingJoinPoint proceedingJoinPoint
    // 环绕通知  环绕通知-目标方法-环绕通知
    @Around("execution(* com.javaee.ex05.service.impl.BookServiceImpl.discount(..))")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知开始 aroundAdvice");
        // 执行目标方法
        Object object = proceedingJoinPoint.proceed();
        System.out.println("环绕通知结束 aroundAdvice");
        return object;
    }
    // 后置通知  @After  需要在subscribe方法执行之后执行
    @After("execution(* com.javaee.ex05.service.impl.BookServiceImpl.subscribe(..))")
    public void afterAdvice(JoinPoint joinPoint) {
        System.out.println("后置通知 afterAdvice");
        System.out.println("目标类：" + joinPoint.getTarget());
        System.out.println("目标方法：" + joinPoint.getSignature().getName());
    }
    // 后置返回通知
    @AfterReturning("pointcut()")
    public void afterReturningAdvice(JoinPoint joinPoint) {
        System.out.println("后置返回通知 afterReturningAdvice");
    }
    // 异常通知
    @AfterThrowing(pointcut = "pointcut()", throwing = "e")
    public void exceptionAdvice(Exception e) {
        System.out.println("异常通知 exceptionAdvice ,异常信息是：" + e.toString());
    }
}
